package com.eian.boot.common.id.generator.segment;

import com.eian.boot.common.id.model.Segment;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 号段生成器抽象类
 *
 * @author alex.meng
 */
public abstract class AbstractSegmentGenerator {

    /**
     * 号段缓存（按业务类型区分）
     */
    protected final Map<String, Segment> segmentCache = new ConcurrentHashMap<>();

    /**
     * 锁映射（按业务类型区分）
     */
    protected final Map<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();

    /**
     * 获取下一个ID
     *
     * @param bizType 业务类型
     * @return 下一个ID
     */
    public long nextId(String bizType) {
        // 先尝试从缓存获取
        Segment segment = segmentCache.get(bizType);
        if (segment != null && segment.hasNext()) {
            Long nextId = segment.getNextId();
            if (nextId != null) {
                return nextId;
            }
        }

        // 缓存不可用，需要获取新的号段
        ReentrantLock lock = lockMap.computeIfAbsent(bizType, k -> new ReentrantLock());
        lock.lock();
        try {
            // 双重检查
            segment = segmentCache.get(bizType);
            if (segment != null && segment.hasNext()) {
                Long nextId = segment.getNextId();
                if (nextId != null) {
                    return nextId;
                }
            }

            // 获取新的号段
            segment = fetchNewSegment(bizType);
            segmentCache.put(bizType, segment);

            // 返回第一个ID
            Long nextId = segment.getNextId();
            if (nextId == null) {
                throw new IllegalStateException("获取ID失败：号段无效");
            }
            return nextId;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 获取新的号段（由子类实现）
     *
     * @param bizType 业务类型
     * @return 号段对象
     */
    protected abstract Segment fetchNewSegment(String bizType);
}

